﻿using System;
using System.Collections.Generic;
using System.Text;
using Pixysoft.Framework.XSchEmA.Entity;
using Pixysoft.Framework.XSchEmA.Aspect;

namespace Pixysoft.Framework.XSchEmA.Hinter
{
    /// <summary>
    /// 不使用域，因为担心初始化的数据和方法传入的数据不同步。全部依赖借口则避免
    /// </summary>
    class SmartHinter : ISmartHinter
    {
        private SmartHinter() { }
        private static SmartHinter instance;
        public static SmartHinter Instance
        {
            get
            {
                lock (typeof(SmartHinter))
                {
                    if (instance == null)
                        instance = new SmartHinter();
                    return instance;
                }
            }
        }

        /// <summary>
        /// 取得能够满足此表列集合 主键、唯一约束，作为外键目标对象
        /// </summary>
        /// <param name="database"></param>
        /// <param name="ftable"></param>
        /// <param name="fcolumns"></param>
        /// <returns></returns>
        public List<IConstraintSchema> GetForeignConstraintList(DatabaseSchema database, TableSchema ftable, List<ColumnSchema> fcolumns)
        {
            List<IConstraintSchema> consList = new List<IConstraintSchema>();

            if (database == null || ftable == null)
                return consList;

            if (fcolumns == null || fcolumns.Count == 0)
                return consList;

            if (database.IsForeignKey(fcolumns))
                return consList;

            foreach (PrimaryKeySchema pk in database.PrimaryKeys)
                if (SchemaUtility.EuqalsDatetype(pk.Columns, fcolumns) && !consList.Contains(pk))
                    consList.Add(pk);

            foreach (UniqueSchema unique in database.Uniques)
                if (SchemaUtility.EuqalsDatetype(unique.Columns, fcolumns) && !consList.Contains(unique))
                    consList.Add(unique);

            foreach (IndexSchema index in database.Indexs)
                if (SchemaUtility.EuqalsDatetype(index.Columns, fcolumns) && !consList.Contains(index))
                    consList.Add(index);

            List<IConstraintSchema> removeList = new List<IConstraintSchema>();

            foreach (IConstraintSchema cons in consList)//自引用
            {
                if (cons.Table == ftable)
                    removeList.Add(cons);
            }

            foreach (IConstraintSchema cons in removeList)
                consList.Remove(cons);


            removeList.Clear();

            List<TableSchema> ftableList = database.GetBeingForeignTableChain(ftable);//循环外键

            foreach (IConstraintSchema cons in consList)
                if (ftableList.Contains(cons.Table))
                    removeList.Add(cons);

            foreach (IConstraintSchema cons in removeList)
                consList.Remove(cons);

            return consList;
        }

        /// <summary>
        /// 取得当前字段的合法datatype，如果存在外键，需要看外表是否存在了only datatype!
        /// </summary>
        /// <param name="dataType"></param>
        /// <param name="database"></param>
        /// <param name="table"></param>
        /// <param name="column"></param>
        /// <returns></returns>
        public List<string> GetDataTypeList(ISchemaAspect aspect, DatabaseSchema database, TableSchema table, ColumnSchema column)
        {
            List<string> datatypeList = aspect.GetDataTypeList();

            foreach (ColumnSchema tcolumn in table.Columns)
            {
                if (tcolumn == column)
                    continue;

                if (aspect.IsUniqueDataType(tcolumn.DataType) && datatypeList.Contains(tcolumn.DataType.DataType))//Only One Special DataType
                    datatypeList.Remove(tcolumn.DataType.DataType);

            }

            if (aspect.IsUniqueDataType(column.DataType))//只要我是only Datatype，则不需要检查fk关系，因为对方一定满足
                return datatypeList;


            foreach (TableSchema pTable in database.GetForeignTableChain(table))
            {
                if (pTable == table)
                    continue;

                foreach (ColumnSchema pcolumn in pTable.Columns)
                {
                    if (aspect.IsUniqueDataType(pcolumn.DataType) && datatypeList.Contains(pcolumn.DataType.DataType))//Only One Special DataType
                        datatypeList.Remove(pcolumn.DataType.DataType);
                }
            }

            return datatypeList;
        }

    }
}
